package com.bdq.interaction.domain.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.bdq.common.entity.common.PageResult;
import com.bdq.common.enums.InteractionTypeEnum;
import com.bdq.common.enums.YesOrNoEnum;
import com.bdq.common.utils.StaticFileUtil;
import com.bdq.interaction.domain.model.dto.*;
import com.bdq.interaction.domain.model.dto.req.*;
import com.bdq.interaction.domain.service.InteractionDomainService;
import com.bdq.interaction.infrastructure.cache.InteractionCache;
import com.bdq.interaction.infrastructure.model.dto.cache.InteractionNumCacheDTO;
import com.bdq.interaction.infrastructure.model.dto.cache.InteractionNumCacheListDTO;
import com.bdq.interaction.infrastructure.model.dto.cache.InteractionVoteNumCacheDTO;
import com.bdq.interaction.infrastructure.persistence.mysql.pojo.InteractionComment;
import com.bdq.interaction.infrastructure.persistence.mysql.pojo.InteractionSingle;
import com.bdq.interaction.infrastructure.persistence.mysql.pojo.InteractionVote;
import com.bdq.interaction.infrastructure.persistence.mysql.service.InteractionCommentService;
import com.bdq.interaction.infrastructure.persistence.mysql.service.InteractionSingleService;
import com.bdq.interaction.infrastructure.persistence.mysql.service.InteractionVoteService;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * @author malei
 * @date 2024-05-14 15:03
 */
@Service
public class InteractionDomainServiceImpl implements InteractionDomainService {

    @Resource
    private InteractionSingleService interactionSingleService;

    @Resource
    private InteractionVoteService interactionVoteService;

    @Resource
    private InteractionCommentService interactionCommentService;

    @Override
    public Boolean interactionNumInit(InteractionNumInitReqDTO reqDTO) {
        InteractionCache.interactionNumInit(reqDTO.getContentId());
        return true;
    }

    @Override
    public Boolean voteInit(VoteInitReqDTO reqDTO) {
        InteractionCache.voteInit(reqDTO.getContentId(), reqDTO.getContentVoteOptionIds());
        return true;
    }

    @Override
    public Boolean view(ViewReqDTO reqDTO) {
        // 0 是否存在
        InteractionSingle data = interactionSingleService.getData(reqDTO.getUserId(), reqDTO.getContentId(), InteractionTypeEnum.VIEW);
        if (Objects.nonNull(data)) {
            return true;
        }
        // 1 存储数据库
        InteractionSingle interactionSingle = new InteractionSingle();
        interactionSingle.setContentId(reqDTO.getContentId());
        interactionSingle.setContentUserId(reqDTO.getContentUserId());
        interactionSingle.setUserId(reqDTO.getUserId());
        interactionSingle.setType(InteractionTypeEnum.VIEW.getCode());
        interactionSingleService.save(interactionSingle);
        // 2 缓存更新
        InteractionCache.viewNumAdd(reqDTO.getContentId());
        // 3 已浏览更新
        InteractionCache.viewedAdd(reqDTO.getUserId(), reqDTO.getContentId());
        return true;
    }

    @Override
    public Boolean like(LikeReqDTO reqDTO) {
        // 0 是否存在
        InteractionSingle data = interactionSingleService.getData(reqDTO.getUserId(), reqDTO.getContentId(), InteractionTypeEnum.LIKE);
        if (Objects.nonNull(data)) {
            return true;
        }
        // 1 存储数据库
        InteractionSingle interactionSingle = new InteractionSingle();
        interactionSingle.setContentId(reqDTO.getContentId());
        interactionSingle.setContentUserId(reqDTO.getContentUserId());
        interactionSingle.setUserId(reqDTO.getUserId());
        interactionSingle.setType(InteractionTypeEnum.LIKE.getCode());
        interactionSingleService.save(interactionSingle);
        // 2 缓存更新
        InteractionCache.likeNumAdd(reqDTO.getContentId());
        return true;
    }

    @Override
    public Boolean cancelLike(LikeCancelReqDTO reqDTO) {
        // 1 删除数据
        interactionSingleService.cancelLike(reqDTO.getContentId(), reqDTO.getUserId());
        // 2 缓存更新
        InteractionCache.likeNumSubtract(reqDTO.getContentId());
        return true;
    }

    @Override
    public Boolean collect(CollectReqDTO reqDTO) {
        // 0 是否存在
        InteractionSingle data = interactionSingleService.getData(reqDTO.getUserId(), reqDTO.getContentId(), InteractionTypeEnum.COLLECT);
        if (Objects.nonNull(data)) {
            return true;
        }
        // 1 存储数据库
        InteractionSingle interactionSingle = new InteractionSingle();
        interactionSingle.setContentId(reqDTO.getContentId());
        interactionSingle.setContentUserId(reqDTO.getContentUserId());
        interactionSingle.setUserId(reqDTO.getUserId());
        interactionSingle.setType(InteractionTypeEnum.COLLECT.getCode());
        interactionSingleService.save(interactionSingle);
        // 2 缓存更新
        InteractionCache.collectNumAdd(reqDTO.getContentId());
        return true;
    }

    @Override
    public Boolean cancelCollect(CollectCancelReqDTO reqDTO) {
        // 1 删除数据
        interactionSingleService.cancelCollect(reqDTO.getContentId(), reqDTO.getUserId());
        // 2 缓存更新
        InteractionCache.collectNumSubtract(reqDTO.getContentId());
        return true;
    }

    @Override
    public Boolean signUp(SignUpReqDTO reqDTO) {
        // 0 是否存在
        InteractionSingle data = interactionSingleService.getData(reqDTO.getUserId(), reqDTO.getContentId(), InteractionTypeEnum.SIGN_UP);
        if (Objects.nonNull(data)) {
            return true;
        }
        // 1 存储数据库
        InteractionSingle interactionSingle = new InteractionSingle();
        interactionSingle.setContentId(reqDTO.getContentId());
        interactionSingle.setContentUserId(reqDTO.getContentUserId());
        interactionSingle.setUserId(reqDTO.getUserId());
        interactionSingle.setType(InteractionTypeEnum.SIGN_UP.getCode());
        interactionSingleService.save(interactionSingle);
        // 2 缓存更新
        InteractionCache.signUpNumAdd(reqDTO.getContentId());
        return true;
    }

    @Override
    public Boolean vote(VoteReqDTO reqDTO) {
        InteractionVote data = interactionVoteService.getData(reqDTO.getUserId(), reqDTO.getContentId());
        if (Objects.nonNull(data)) {
            return true;
        }
        // 1 存储数据库
        InteractionVote interactionVote = new InteractionVote();
        interactionVote.setContentId(reqDTO.getContentId());
        interactionVote.setContentUserId(reqDTO.getContentUserId());
        interactionVote.setContentVoteOptionId(reqDTO.getContentVoteOptionId());
        interactionVote.setUserId(reqDTO.getUserId());
        interactionVoteService.save(interactionVote);
        // 2 缓存更新
        InteractionCache.voteNumAdd(reqDTO.getContentId(), reqDTO.getContentVoteOptionId());
        return true;
    }

    @Override
    public Boolean comment(CommentReqDTO reqDTO) {
        // 1 存储数据库
        InteractionComment interactionComment = Convert.convert(InteractionComment.class, reqDTO);
        interactionCommentService.save(interactionComment);
        // 2 更新子评论数量
        if (Objects.nonNull(reqDTO.getParentCommentId())) {
            InteractionComment comment = interactionCommentService.getById(reqDTO.getParentCommentId());
            comment.setChildCommentNum(comment.getChildCommentNum() + 1);
            interactionCommentService.updateById(comment);
        }
        // 3 更新缓存
        InteractionCache.commentNumAdd(reqDTO.getContentId());
        return true;
    }

    @Override
    public InteractionDataGetDomainDTO getData(InteractionDataGetReqDTO reqDTO) {
        // 1 获取当前用户交互数据
        // 1.1 简单交互
        List<InteractionSingle> interactionSingleList = interactionSingleService.getData(reqDTO.getUserId(), reqDTO.getContentId());
        // 1.2 投票
        InteractionVote interactionVote = interactionVoteService.getData(reqDTO.getUserId(), reqDTO.getContentId());

        // 2 获取累计数据
        // 2.1 简单交互累计数据
        InteractionNumCacheDTO interactionNumCacheDTO = InteractionCache.getInteractionNum(reqDTO.getContentId());
        // 2.2 获取投票交互累计数据
        List<InteractionVoteNumCacheDTO> interactionVoteNumCacheDTOList = InteractionCache.getInteractionVoteNum(reqDTO.getContentId());

        // 3 响应结果
        InteractionDataGetDomainDTO interactionDataGetDomainDTO = new InteractionDataGetDomainDTO();
        List<Integer> typeList = interactionSingleList.stream().map(InteractionSingle::getType).collect(Collectors.toList());
        if (typeList.contains(InteractionTypeEnum.LIKE.getCode())) {
            interactionDataGetDomainDTO.setIsLike(YesOrNoEnum.YES.getCode());
        }else {
            interactionDataGetDomainDTO.setIsLike(YesOrNoEnum.NO.getCode());
        }
        if (typeList.contains(InteractionTypeEnum.COLLECT.getCode())) {
            interactionDataGetDomainDTO.setIsCollect(YesOrNoEnum.YES.getCode());
        }else {
            interactionDataGetDomainDTO.setIsCollect(YesOrNoEnum.NO.getCode());
        }
        if (typeList.contains(InteractionTypeEnum.SIGN_UP.getCode())) {
            interactionDataGetDomainDTO.setIsSignUp(YesOrNoEnum.YES.getCode());
        }else {
            interactionDataGetDomainDTO.setIsSignUp(YesOrNoEnum.NO.getCode());
        }
        if (typeList.contains(InteractionTypeEnum.VIEW.getCode())) {
            interactionDataGetDomainDTO.setIsView(YesOrNoEnum.YES.getCode());
        }else {
            interactionDataGetDomainDTO.setIsView(YesOrNoEnum.NO.getCode());
        }
        if (Objects.nonNull(interactionVote)) {
            interactionDataGetDomainDTO.setIsVote(YesOrNoEnum.YES.getCode());
        }else {
            interactionDataGetDomainDTO.setIsVote(YesOrNoEnum.NO.getCode());
        }
        if (Objects.nonNull(interactionNumCacheDTO)) {
            BeanUtils.copyProperties(interactionNumCacheDTO, interactionDataGetDomainDTO);
        }
        List<InteractionVoteOptionDataGetDomainDTO> voteOptionDataGetDomainDTOS = new ArrayList<>();
        for (InteractionVoteNumCacheDTO interactionVoteNumCacheDTO : interactionVoteNumCacheDTOList) {
            InteractionVoteOptionDataGetDomainDTO interactionVoteOptionDataGetDomainDTO = new InteractionVoteOptionDataGetDomainDTO();
            interactionVoteOptionDataGetDomainDTO.setId(interactionVoteNumCacheDTO.getContentVoteOptionId());
            interactionVoteOptionDataGetDomainDTO.setVoteNum(interactionVoteNumCacheDTO.getVoteNum());
            voteOptionDataGetDomainDTOS.add(interactionVoteOptionDataGetDomainDTO);
        }
        calculateRatios(voteOptionDataGetDomainDTOS);
        interactionDataGetDomainDTO.setVoteOptions(voteOptionDataGetDomainDTOS);
        return interactionDataGetDomainDTO;
    }

    @Override
    public List<InteractionDataListDomainDTO> listData(Long userId, List<Long> contentIds) {
        // 1 获取当前用户交互数据
        List<InteractionSingle> interactionSingleList = interactionSingleService.listData(userId, contentIds);

        // 2 返回结果
        List<InteractionDataListDomainDTO> interactionDataListDomainDTOS = new ArrayList<>();
        for (Long contentId : contentIds) {
            InteractionDataListDomainDTO interactionDataListDomainDTO = new InteractionDataListDomainDTO();
            interactionDataListDomainDTO.setContentId(contentId);

            // 2.1 累计交互数据
            InteractionNumCacheDTO interactionNumCacheDTO = InteractionCache.getInteractionNum(contentId);
            BeanUtils.copyProperties(interactionNumCacheDTO, interactionDataListDomainDTO);

            // 2.2 当前用户交互数据
            List<Integer> typeList = interactionSingleList.stream().filter(e -> e.getContentId().equals(contentId)).map(InteractionSingle::getType).collect(Collectors.toList());
            if (typeList.contains(InteractionTypeEnum.LIKE.getCode())) {
                interactionDataListDomainDTO.setIsLike(YesOrNoEnum.YES.getCode());
            }else {
                interactionDataListDomainDTO.setIsLike(YesOrNoEnum.NO.getCode());
            }
            if (typeList.contains(InteractionTypeEnum.COLLECT.getCode())) {
                interactionDataListDomainDTO.setIsCollect(YesOrNoEnum.YES.getCode());
            }else {
                interactionDataListDomainDTO.setIsCollect(YesOrNoEnum.NO.getCode());
            }
            if (typeList.contains(InteractionTypeEnum.VIEW.getCode())) {
                interactionDataListDomainDTO.setIsView(YesOrNoEnum.YES.getCode());
            }else {
                interactionDataListDomainDTO.setIsView(YesOrNoEnum.NO.getCode());
            }

            interactionDataListDomainDTOS.add(interactionDataListDomainDTO);
        }
        return interactionDataListDomainDTOS;
    }

    /**
     * 计算占比
     *
     * @param voteOptions
     */
    public void calculateRatios(List<InteractionVoteOptionDataGetDomainDTO> voteOptions) {
        // 校验
        if (voteOptions.isEmpty()) {
            return;
        }

        // 计算总投票数
        int totalVotes = voteOptions.stream().mapToInt(InteractionVoteOptionDataGetDomainDTO::getVoteNum).sum();
        if (totalVotes == 0) {
            for (InteractionVoteOptionDataGetDomainDTO voteOption : voteOptions) {
                voteOption.setRatio("0%");
            }
            return;
        }
        BigDecimal totalVotesBD = BigDecimal.valueOf(totalVotes);

        // 计算每个选项的占比
        BigDecimal totalRatio = BigDecimal.ZERO;
        InteractionVoteOptionDataGetDomainDTO maxOption = null;
        BigDecimal maxRatio = BigDecimal.ZERO;
        for (InteractionVoteOptionDataGetDomainDTO option : voteOptions) {
            BigDecimal voteNumBD = BigDecimal.valueOf(option.getVoteNum());
            BigDecimal ratio = voteNumBD.divide(totalVotesBD, 2, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
            option.setRatio(ratio.toString().concat("%"));

            totalRatio = totalRatio.add(ratio.setScale(2, RoundingMode.HALF_UP));
            if (ratio.compareTo(maxRatio) > 0) {
                maxRatio = ratio;
                maxOption = option;
            }
        }

        // 调整占比使其和为100%
        BigDecimal adjustment = BigDecimal.valueOf(100).subtract(totalRatio);
        if (maxOption != null && adjustment.compareTo(BigDecimal.ZERO) != 0) {
            BigDecimal newRatio = maxRatio.add(adjustment);
            maxOption.setRatio(newRatio.setScale(2, RoundingMode.HALF_UP) + "%");
        }
    }

    @Override
    public PageResult<ParentCommentPageDomainDTO> pageParentComment(ParentCommentPageReqDTO reqDTO) {
        // 1 分页查询评论
        IPage<InteractionComment> parentCommentPage = interactionCommentService.pageParentComment(reqDTO.getContentId(), reqDTO.getPageNo(), reqDTO.getPageSize());
        List<InteractionComment> interactionCommentList = parentCommentPage.getRecords();

        // 2 返回结果
        PageResult<ParentCommentPageDomainDTO> pageResult = new PageResult<>();
        pageResult.setTotal(parentCommentPage.getTotal());
        if (CollUtil.isEmpty(interactionCommentList)) {
            pageResult.setList(Collections.emptyList());
            return pageResult;
        }
        List<ParentCommentPageDomainDTO> parentCommentPageDomainDTOS = Convert.toList(ParentCommentPageDomainDTO.class, interactionCommentList);
        for (ParentCommentPageDomainDTO parentCommentPageDomainDTO : parentCommentPageDomainDTOS) {
            parentCommentPageDomainDTO.setCommentUserAvatar(StaticFileUtil.domainConcat(parentCommentPageDomainDTO.getCommentUserAvatar()));
            parentCommentPageDomainDTO.setTime(commentTimeConvert(parentCommentPageDomainDTO.getCreateTime()));
        }
        pageResult.setList(parentCommentPageDomainDTOS);
        return pageResult;
    }

    @Override
    public PageResult<ChildCommentPageDomainDTO> pageChildComment(ChildCommentPageReqDTO reqDTO) {
        // 1 分页查询评论
        IPage<InteractionComment> childCommentPage = interactionCommentService.pageChildComment(reqDTO.getParentCommentId(), reqDTO.getPageNo(), reqDTO.getPageSize());
        List<InteractionComment> interactionCommentList = childCommentPage.getRecords();

        // 2 返回结果
        PageResult<ChildCommentPageDomainDTO> pageResult = new PageResult<>();
        pageResult.setTotal(childCommentPage.getTotal());
        if (CollUtil.isEmpty(interactionCommentList)) {
            pageResult.setList(Collections.emptyList());
            return pageResult;
        }
        List<ChildCommentPageDomainDTO> childCommentPageDomainDTOS = Convert.toList(ChildCommentPageDomainDTO.class, interactionCommentList);
        for (ChildCommentPageDomainDTO childCommentPageDomainDTO : childCommentPageDomainDTOS) {
            childCommentPageDomainDTO.setCommentUserAvatar(StaticFileUtil.domainConcat(childCommentPageDomainDTO.getCommentUserAvatar()));
            childCommentPageDomainDTO.setTime(commentTimeConvert(childCommentPageDomainDTO.getCreateTime()));
        }
        pageResult.setList(childCommentPageDomainDTOS);
        return pageResult;
    }

    /**
     * 评论时间转换
     *
     * @param time
     * @return
     */
    private String commentTimeConvert(LocalDateTime time) {

        LocalDateTime now = LocalDateTime.now();
        Duration duration = Duration.between(time, now);

        long seconds = duration.getSeconds();
        long minutes = duration.toMinutes();
        long hours = duration.toHours();
        long days = duration.toDays();

        if (seconds < 60) {
            return seconds + "秒前";
        } else if (minutes < 60) {
            return minutes + "分钟前";
        } else if (hours < 24) {
            return hours + "小时前";
        } else if (days <= 3) {
            return days + "天前";
        } else {
            return time.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }
    }
}
